﻿using System;
using System.Collections.Generic;
using System.Linq;
//using DynamicLINQ;
using System.Text;
using Lab2___Mineria_de_datos.Modelo;

namespace Lab2___Mineria_de_datos.Main
{
    /// <summary>
    /// Funciones de restricción
    /// </summary>
    public class Restricciones
    {
        private Entities db;
        private int total_instancias;
        //private float soporte_minimo;

        public Restricciones(Entities DB)//, float soporte_minimo)
        {
            this.db = DB;
            total_instancias = db.MEDICION.Count();
            //this.soporte_minimo = soporte_minimo;
        }

        /// <summary>
        /// Sub-clase ocuapda con la única finalidad de proveer un comparador de tuplas/combinatoria.
        /// </summary>
        internal class Comparador
        {
            public readonly int id_atributo;
            public readonly int id_rango;

            public Comparador(int atributo, int rango)
            {
                this.id_atributo = atributo;
                this.id_rango = rango;
            }
        }


        internal class MedicionEqualityComparer : IEqualityComparer<MEDICION>
        {

            public bool Equals(MEDICION b1, MEDICION b2)
            {
                return b1.ID_ATRIBUTO == b2.ID_ATRIBUTO && b1.ID_RANGO == b2.ID_RANGO;
            }

            public int GetHashCode(MEDICION bx)
            {
                return bx.GetHashCode();
                //return hCode.GetHashCode();
            }

        }

        /// <summary>
        /// Cálculo del soporte de una regla.
        /// Para realizar la comparación entre tupla y combinatoria se mueve la tupla hacia un HashSet, disminuyendo el orden de complejidad de la operación.
        /// O(n) = T*D | T := largo de la tupla ; D := largo del antecedente
        /// </summary>
        /// <param name="antecedente">Antecedente de la regla</param>
        /// <returns>Soporte de la regla</returns>
        public float Soporte(RANGO[] antecedente)
        {
            //var mediciones = db.MEDICION.ToArray();
            int soporte = 0;

            foreach (TUPLA tupla in db.TUPLA)
            {
                //HashSet<Comparador> tuplaHash = new HashSet<Comparador>(tupla.MEDICION.Select(m => new Comparador(m.ID_ATRIBUTO, m.ID_RANGO)));
                //bool esta = antecedente.Select(a => new Comparador(a.ID_ATRIBUTO, a.ID_RANGO)).All(i => tuplaHash.Contains(i));

                //var list1 = tupla.MEDICION.Select(m => new Comparador(m.ID_ATRIBUTO, m.ID_RANGO));
                //var list2 = antecedente.Select(a => new Comparador(a.ID_ATRIBUTO, a.ID_RANGO));

                var list1 = tupla.MEDICION.AsParallel();//.Select(t => t);
                var list2 = antecedente.SelectMany(a => a.MEDICION).AsParallel();

                bool esta = list1.Intersect(list2, new MedicionEqualityComparer()).Count() == list1.Count();

                if (esta)
                {
                    soporte++;
                }
            }

            //int atrb1 = antecedente[0].ID_ATRIBUTO;
            //int rang1 = antecedente[0].ID_RANGO;

            //int atrb2 = antecedente[1].ID_ATRIBUTO;
            //int rang2 = antecedente[1].ID_RANGO;

            return soporte / total_instancias;
        }

        public float Confianza(RANGO[] antecedente, RANGO consecuente)
        {
            throw new NotImplementedException();
        }

        public float Confianza(RANGO[] antecedente, RANGO consecuente, float soporte)
        {
            throw new NotImplementedException();
        }
    }
}
